package com.SRMS.service;

import com.SRMS.common.MessageType;
import com.SRMS.common.User;
import com.SRMS.common.Message;
import com.SRMS.domain.Administrator;
import com.SRMS.domain.Student;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author Albert
 * @version 1.0
 * @date 2023/12/24-0:23
 * @describe 这是服务器，在监听9999，等待客户端的连接，并保持通信
 */
public class SRMSServer {
    private ServerSocket ss = null;
    private StudentService studentService = new StudentService();
    private AdministratorService administratorService = new AdministratorService();

    public SRMSServer() {
        System.out.println("服务端正在 9999 端口监听...");
        try {
            ss = new ServerSocket(9999);

            while(true){ //当和某个客户端连接后，会继续监听，因此while
                Socket socket = ss.accept();//如果没有客户端连接，将会阻塞在这里
                //得到socket关联的对象输入流
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                User u = (User) ois.readObject();//读取客户端发送的User对象
                //得到socket关联的对象输出流
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                //创建一个message对象，准备回复客户端
                Message message = new Message();
                //验证
                int identity = authenticate(u.getId(), u.getPassword());
                if(identity != 2){//登录验证
                    System.out.println("用户：" + u.getId() + " 密码：" + u.getPassword()+ " 验证成功");
                    if(identity == 0) {
                        message.setMesType(MessageType.STUDENT_LOGIN_SUCCEED);
                    } else {
                        message.setMesType(MessageType.ADMINISTRATOR_LOGIN_SUCCEED);
                    }
                    //将message对象回复客户端
                    oos.writeObject(message);
                    //创建一个线程，和客户端保持通信，该线程需要持有socket对象
                    ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, u.getId());
                    serverConnectClientThread.setStudentService(studentService);
                    serverConnectClientThread.setAdministratorService(administratorService);
                    //启动线程
                    serverConnectClientThread.start();
                    //把该线程对象放入一个集合，便于管理
                    ManageClientThreads.addServerConnectClientThread(u.getId(), serverConnectClientThread);
                } else {//登录失败
                    System.out.println("用户：" + u.getId() + " 密码：" + u.getPassword()+ " 验证失败");
                    message.setMesType(MessageType.LOGIN_FAIL);
                    //将message对象回复客户端
                    oos.writeObject(message);
                    //关闭socket
                    socket.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            //退出while循环，说明不再监听，应该关闭ServerSocket
            try {
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 验证用户身份
     *
     * @param userId 账号
     * @param password 密码
     * @return ‘0’代表学生，‘1’代表管理员，‘2’代表验证失败
     */
    private int authenticate(String userId, String password) {
        if (checkStudent(userId, password)) {
            return 0;
        } else if (checkAdministrator(userId, password)) {
            return 1;
        } else {
            return 2;
        }
    }

    /**
     * 检查是否为学生
     *
     * @param stuId
     * @param pwd
     * @return
     */
    public boolean checkStudent(String stuId, String pwd) {
        Student student = studentService.getStudentByIdAndPwd(stuId, pwd);
        return student != null;
    }

    /**
     * 检查是否为管理员
     *
     * @param adminId
     * @param pwd
     * @return
     */
    public boolean checkAdministrator(String adminId, String pwd) {
        Administrator administrator = administratorService.getAdministratorByIdAndPwd(adminId, pwd);
        return administrator != null;
    }


}
